﻿using System.Collections.Generic;
using System.Linq;
using EcsRx.Groups;
using TFramework.ECS.Entity;
using TFramework.ECS.Group.Manager;

namespace TFramework.Extensions
{
    public static class GroupLookupExtensions
    {
        public static bool ContainsAllRequiredComponents(this GroupLookup group, params int[] componentTypeIds)
        { return ContainsAllRequiredComponents(group, (IReadOnlyList<int>)componentTypeIds); }

        public static bool ContainsAllRequiredComponents(this GroupLookup group, IReadOnlyList<int> componentTypeIds)
        {
            for (var i = group.RequiredComponents.Length - 1; i >= 0; i--)
            {
                if (!componentTypeIds.Contains(group.RequiredComponents[i]))
                { return false; }
            }

            return true;
        }

        public static bool ContainsAllRequiredComponents(this GroupLookup group, IEntity entity)
        { return entity.HasAllComponents(group.RequiredComponents); }

        public static bool ContainsAnyRequiredComponents(this GroupLookup group, params int[] componentTypeIds)
        { return ContainsAnyRequiredComponents(group, (IReadOnlyList<int>)componentTypeIds); }

        public static bool ContainsAnyRequiredComponents(this GroupLookup group, IReadOnlyList<int> componentTypes)
        {
            for (var i = group.RequiredComponents.Length - 1; i >= 0; i--)
            {
                for (var j = componentTypes.Count - 1; j >= 0; j--)
                {
                    if (group.RequiredComponents[i] == componentTypes[j])
                    { return true; }
                }
            }

            return false;
        }

        public static bool ContainsAnyRequiredComponents(this GroupLookup group, IEntity entity)
        { return entity.HasAnyComponents(group.RequiredComponents); }

        public static bool ContainsAnyExcludedComponents(this GroupLookup group, params int[] componentTypes)
        { return ContainsAnyExcludedComponents(group, (IReadOnlyList<int>)componentTypes); }

        public static bool ContainsAnyExcludedComponents(this GroupLookup group, IReadOnlyList<int> componentTypes)
        { return group.ExcludedComponents.Any(componentTypes.Contains); }

        public static bool ContainsAnyExcludedComponents(this GroupLookup group, IEntity entity)
        { return entity.HasAnyComponents(group.ExcludedComponents); }

        public static bool ContainsAny(this GroupLookup group, params int[] components)
        { return ContainsAny(group, (IReadOnlyList<int>)components); }

        public static bool ContainsAny(this GroupLookup group, IReadOnlyList<int> components)
        {
            var requiredContains = group.ContainsAnyRequiredComponents(components);
            if (requiredContains) { return true; }

            return group.ContainsAnyExcludedComponents(components);
        }

        public static bool Matches(this GroupLookup GroupLookup, IEntity entity)
        {
            if (GroupLookup.ExcludedComponents.Length == 0)
            { return ContainsAllRequiredComponents(GroupLookup, entity); }

            return ContainsAllRequiredComponents(GroupLookup, entity) && !ContainsAnyExcludedComponents(GroupLookup, entity);
        }

        public static bool Matches(this GroupLookup GroupLookup, params int[] componentTypes)
        { return Matches(GroupLookup, (IReadOnlyList<int>)componentTypes); }

        public static bool Matches(this GroupLookup GroupLookup, IReadOnlyList<int> componentTypes)
        {
            if (GroupLookup.ExcludedComponents.Length == 0)
            { return ContainsAllRequiredComponents(GroupLookup, componentTypes); }

            return ContainsAllRequiredComponents(GroupLookup, componentTypes) && !ContainsAnyExcludedComponents(GroupLookup, componentTypes);
        }
    }
}